import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
from BlockChain.分模块实现简单区块链.BlockCoin_dada import Dada_BlockCoin, InvalidBlockCoin
from BlockChain.分模块实现简单区块链.Block_dada import Block
from BlockChain.分模块实现简单区块链.Message import DaDaMessage, InvalidMessage
from BlockChain.分模块实现简单区块链.Transaction import Transaction

class BlockChainApp:
    def __init__(self, root):
        self.root = root
        self.root.title("区块链可视化")
        self.blockchain = Dada_BlockCoin()
        self.current_block_transactions = []
        self.selected_block_index = None

        # 添加滚动条
        self.canvas_frame = tk.Frame(root)
        self.canvas_frame.pack(expand=tk.YES, fill=tk.BOTH)

        self.scrollbar_x = tk.Scrollbar(self.canvas_frame, orient=tk.HORIZONTAL)
        self.scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)

        self.scrollbar_y = tk.Scrollbar(self.canvas_frame)
        self.scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)

        # 区块链信息显示框
        self.canvas = tk.Canvas(self.canvas_frame, width=800, yscrollcommand=self.scrollbar_y.set, xscrollcommand=self.scrollbar_x.set)
        self.canvas.pack(side=tk.LEFT, expand=tk.YES, fill=tk.BOTH)

        self.scrollbar_x.config(command=self.canvas.xview)
        self.scrollbar_y.config(command=self.canvas.yview)

        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))

        # 交易信息输入框
        self.payer_label = tk.Label(root, text="付款方:")
        self.payer_label.pack()
        self.payer_entry = tk.Entry(root)
        self.payer_entry.pack()

        self.recer_label = tk.Label(root, text="收款方:")
        self.recer_label.pack()
        self.recer_entry = tk.Entry(root)
        self.recer_entry.pack()

        self.money_label = tk.Label(root, text="金额:")
        self.money_label.pack()
        self.money_entry = tk.Entry(root)
        self.money_entry.pack()

        # 添加交易按钮
        self.add_transaction_btn = tk.Button(root, text="添加交易", command=self.add_transaction)
        self.add_transaction_btn.pack()

        # 添加区块按钮
        self.add_block_btn = tk.Button(root, text="添加区块", command=self.add_block)
        self.add_block_btn.pack()

        # 模拟篡改按钮
        self.tamper_block_btn = tk.Button(root, text="模拟篡改数据", command=self.tamper_block)
        self.tamper_block_btn.pack()

        # 区块查询框
        self.query_frame = tk.Frame(root)
        self.query_frame.pack()

        self.query_label = tk.Label(self.query_frame, text="查询区块索引:")
        self.query_label.pack(side=tk.LEFT)

        self.query_entry = tk.Entry(self.query_frame)
        self.query_entry.pack(side=tk.LEFT)

        self.query_btn = tk.Button(self.query_frame, text="查询区块", command=self.query_block)
        self.query_btn.pack(side=tk.LEFT)

        # 交易信息显示框
        self.transaction_info_text = tk.Text(root, wrap=tk.WORD, width=60, height=10)
        self.transaction_info_text.pack()

    def add_transaction(self):
        payer = self.payer_entry.get()
        recer = self.recer_entry.get()
        money = self.money_entry.get()

        try:
            money = int(money)
        except ValueError:
            messagebox.showerror("错误", "金额必须为整数")
            return

        if payer and recer and money > 0:
            transaction = Transaction(payer, recer, money)
            self.current_block_transactions.append(DaDaMessage(transaction))
            self.update_blockchain_info()
            messagebox.showinfo("成功", "交易添加成功")
        else:
            messagebox.showerror("错误", "请输入有效的交易信息")

    def add_block(self):
        if self.current_block_transactions:
            block = Block(*self.current_block_transactions)
            self.blockchain.add_block(block)
            self.current_block_transactions = []
            self.update_blockchain_info()
            messagebox.showinfo("成功", "区块添加成功")
        else:
            messagebox.showerror("错误", "当前区块没有交易信息")

    def tamper_block(self):
        try:
            block_index = int(input("请输入要篡改的区块索引："))
        except ValueError:
            messagebox.showerror("错误", "请输入有效的区块索引")
            return

        if 0 <= block_index < len(self.blockchain.blockList):
            block = self.blockchain.blockList[block_index]
            if len(block.messageList) > 0:
                # 模拟篡改第一条交易信息
                block.messageList[0].data = "篡改后的交易信息"

                try:
                    self.blockchain.validate()
                except InvalidBlockCoin as e:
                    messagebox.showerror("篡改数据", "区块链数据已被篡改，篡改发生在第{}个区块".format(e.args[0]))
                except InvalidMessage as e:
                    messagebox.showerror("篡改数据", "区块链数据已被篡改，篡改发生在第{}个区块的第{}条交易信息".format(e.args[0][0], e.args[0][1]))
                else:
                    messagebox.showinfo("篡改数据", "区块链数据未被篡改")
                finally:
                    self.update_blockchain_info()
            else:
                messagebox.showerror("错误", "区块中没有交易信息，无法篡改")
        else:
            messagebox.showerror("错误", "区块索引超出范围")

    def query_block(self):
        try:
            block_index = int(self.query_entry.get())
        except ValueError:
            messagebox.showerror("错误", "请输入有效的区块索引")
            return

        if 0 <= block_index < len(self.blockchain.blockList):
            block = self.blockchain.blockList[block_index]
            transactions = "\n".join(str(msg.data) for msg in block.messageList)
            self.transaction_info_text.delete("1.0", tk.END)
            self.transaction_info_text.insert(tk.END, transactions)
            self.selected_block_index = block_index
            messagebox.showinfo("成功", "查询成功")
        else:
            messagebox.showerror("错误", "区块索引超出范围")

    def update_blockchain_info(self):
        self.canvas.delete("all")  # 清空画布上的内容
        x, y = 20, 50  # 区块链的初始位置
        block_width, block_height = 250, 150  # 区块的宽度和高度

        for block in self.blockchain.blockList:
            self.canvas.create_rectangle(x, y, x + block_width, y + block_height, outline="black")  # 绘制区块框
            self.canvas.create_text(x + block_width // 2, y + block_height // 2, text=str(block))  # 显示区块信息

            if block.prev_hash:  # 绘制区块之间的连接线
                prev_x, prev_y = x - block_width, y + block_height // 2
                self.canvas.create_line(prev_x, prev_y, x, y + block_height // 2, fill="red")

            x += block_width + 50  # 每个区块之间留一定的间隔

        # 设置Canvas可滚动范围
        self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))

if __name__ == "__main__":
    root = tk.Tk()
    app = BlockChainApp(root)
    app.root.mainloop()
